package com.j4cf.web.config;

import com.j4cf.auth.shiro.filter.AuthAuthenticationFilter;
import com.j4cf.auth.shiro.filter.AuthSessionForceLogoutFilter;
import com.j4cf.auth.shiro.listener.AuthSessionListener;
import com.j4cf.auth.shiro.realm.AuthRealm;
import com.j4cf.auth.shiro.session.AuthSessionDao;
import com.j4cf.auth.shiro.session.AuthSessionFactory;
import com.j4cf.auth.shiro.session.AuthSessionManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description:
 * @Author: LongRou
 * @CreateDate: 2018 2018/4/26 11:21
 * @Version: 1.0
 **/
@Configuration
public class ShiroConfig {
    //@Value("${spring.redis.shiro.host}")
    //private String host;

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        System.out.println("ShiroConfiguration.shirFilter()");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
        filters.put("authc",authAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(filters);
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        //注意过滤器配置顺序 不能颠倒
        //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了，登出后跳转配置的loginUrl
        filterChainDefinitionMap.put("/logout", "logout");
        // 配置不会被拦截的链接 顺序判断
//        filterChainDefinitionMap.put("/static/**", "anon");
//        filterChainDefinitionMap.put("/sys/**", "anon");
//        filterChainDefinitionMap.put("/dist/**", "anon");
//        filterChainDefinitionMap.put("/sso/nof", "anon");
//        filterChainDefinitionMap.put("/sso/login", "anon");
        filterChainDefinitionMap.put("/admin/**", "authc");
        filterChainDefinitionMap.put("/agent/**", "authc");
        filterChainDefinitionMap.put("/user/**", "authc");
        filterChainDefinitionMap.put("/manage/**", "authc");
        filterChainDefinitionMap.put("/**", "anon");
        //配置shiro默认登录界面地址，前后端分离中登录界面跳转应由前端路由控制，后台仅返回json数据
 //       shiroFilterFactoryBean.setLoginUrl("/sso/unauth");
        // 登录成功后要跳转的链接
//        shiroFilterFactoryBean.setSuccessUrl("/index");
        //未授权界面;
//        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
    //重写authc过滤器
    @Bean
    public AuthAuthenticationFilter authAuthenticationFilter(){
        return new AuthAuthenticationFilter();
    }
    //强制退出会话过滤器
    @Bean
    public AuthSessionForceLogoutFilter authSessionForceLogoutFilter(){
        return new AuthSessionForceLogoutFilter();
    }
    //安全管理器
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(authRealm());
        // 自定义session管理 使用redis
        securityManager.setSessionManager(sessionManager());
        // 自定义缓存实现 使用redis
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }
    //域
    @Bean
    public AuthRealm authRealm() {
        AuthRealm authRealm = new AuthRealm();
        //authRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return authRealm;
    }
    //会话管理器
    //自定义sessionManager
    @Bean
    public SessionManager sessionManager() {
        AuthSessionManager mySessionManager = new AuthSessionManager();
        mySessionManager.setSessionDAO(authSessionDao());
        mySessionManager.setSessionIdCookieEnabled(true);
        mySessionManager.setSessionIdCookie(sessionIdCookie());
        mySessionManager.setSessionValidationSchedulerEnabled(false);

        List<SessionListener> listentrsList = new ArrayList();
        listentrsList.add(authSessionListener());
        mySessionManager.setSessionListeners(listentrsList);
        mySessionManager.setSessionFactory(authSessionFactory());
        return mySessionManager;
    }
    @Bean
    public AuthSessionDao authSessionDao() {
        AuthSessionDao authSessionDao = new AuthSessionDao();
        return authSessionDao;
    }
    //sessionIdCookie
    @Bean
    public SimpleCookie sessionIdCookie() {
        SimpleCookie sessionIdCookie = new SimpleCookie();
        //不会暴露给客户端
        sessionIdCookie.setHttpOnly(true);
        //设置Cookie的过期时间，秒为单位，默认-1表示关闭浏览器时过期Cookie
        sessionIdCookie.setMaxAge(-1);
        //Cookie名称
        sessionIdCookie.setName("j4cf-cookie");
        return sessionIdCookie;
    }
    //会话监听器
    @Bean
    public AuthSessionListener authSessionListener() {
        AuthSessionListener authSessionListener = new AuthSessionListener();
        return authSessionListener;
    }
    //session工厂
    @Bean
    public AuthSessionFactory authSessionFactory() {
        AuthSessionFactory authSessionFactory = new AuthSessionFactory();
        return authSessionFactory;
    }
    //rememberMe管理器
    @Bean
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
        //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度（128 256 512 位）
        rememberMeManager.setCipherKey(org.apache.shiro.codec.Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
        rememberMeManager.setCookie(rememberMeCookie());
        return rememberMeManager;
    }
    //rememberMe缓存cookie
    @Bean
    public SimpleCookie rememberMeCookie() {
        SimpleCookie rememberMeCookie = new SimpleCookie();
        //不会暴露给客户端
        rememberMeCookie.setHttpOnly(true);
        //设置Cookie的过期时间，秒为单位，默认-1表示关闭浏览器时过期Cookie
        rememberMeCookie.setMaxAge(640000);

        rememberMeCookie.setName("j4cf-remeber-cookie");
        return rememberMeCookie;
    }
    //设置SecurityUtils，相当于调用SecurityUtils.setSecurityManager(securityManager)
    @Bean
    public MethodInvokingFactoryBean methodInvokingFactoryBean() {
        MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
        methodInvokingFactoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
        methodInvokingFactoryBean.setArguments(securityManager());
        return methodInvokingFactoryBean;
    }
    /**
     * 开启shiro aop注解支持.
     * 使用代理方式;所以需要开启代码支持;
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator =new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
    //Shiro生命周期处理器
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        LifecycleBeanPostProcessor lifecycleBeanPostProcessor = new LifecycleBeanPostProcessor();
        return lifecycleBeanPostProcessor;
    }

}
